/*
* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* openUBMC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*         http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

#include <gtest/gtest.h>
#include <test_utilities/test_base.h>
#include "interface/network_port/metrics.h"
#include <ncsi_over_mctp/ncsi_over_mctp_mellanox.h>
#include <mctp/mctp.h>
#include <mc/engine.h>
#include <mc/common.h>
#include <ncsi/ncsi_protocol.h>
#include <ncsi/ncsi_socket.h>
#include "mock_ipmi_core.h"
#include <ctime>
#include <thread>
#include <chrono>
#include <functional>
#include <vector>
#include <string>

// 声明外部 MCTP 请求处理器设置函数
namespace dev {
void set_mctp_request_handler(std::function<bool(const mc::dict&, const std::vector<uint8_t>&,
                                                 std::string&)> handler);
}

namespace drivers {
namespace pcie_nic_card {
namespace mellanox {
namespace interface {
namespace test {

namespace {
// 字节序转换辅助函数
constexpr uint16_t host_to_be16(uint16_t value) {
    return static_cast<uint16_t>(((value & 0x00FFU) << 8U) | ((value & 0xFF00U) >> 8U));
}
} // namespace

class metrics_test_service : public mc::engine::service {
public:
    metrics_test_service(const std::string& name) : mc::engine::service(name) {}
};

// ========================= NetworkPort_Metrics测试 =========================
class NetworkPortMetricsTest : public mc::test::TestWithEngine {
protected:
    static void SetUpTestSuite() {
        TestWithEngine::SetUpTestSuite();
        m_test_service = std::make_unique<metrics_test_service>("bmc.openubmc.test_metrics");
        m_test_service->init();
        m_test_service->start();
        
        // 注册 mock IpmiCore 接口，避免真实的 D-Bus 调用
        m_ipmi_core_obj = test_ipmi_core_object::create();
        m_ipmi_core_obj->set_object_path("/bmc/kepler/IpmiCore");
        m_ipmi_core_obj->set_object_name("bmc.kepler.IpmiCore");
        m_test_service->register_object(m_ipmi_core_obj);
    }
    static void TearDownTestSuite() {
        try {
            if (m_ipmi_core_obj && m_test_service) {
                m_test_service->unregister_object(m_ipmi_core_obj);
                m_ipmi_core_obj.reset();
            }
            if (m_test_service) {
                m_test_service->stop();
                m_test_service.reset();
            }
            TestWithEngine::TearDownTestSuite();
        } catch (...) {
            if (m_ipmi_core_obj) {
                m_ipmi_core_obj.reset();
            }
            if (m_test_service) {
                m_test_service.reset();
            }
        }
    }
    void SetUp() override {
        static int test_counter = 0;
        test_counter++;
        std::string object_name =
            "test_metrics_" + std::to_string(test_counter) + "_" + std::to_string(std::time(nullptr));
        std::string position = std::to_string(test_counter + 700);

        m_metrics = mc::make_shared<dev::NetworkPort_Metrics>();

        // 创建真实的 ncsi_over_mctp_mellanox，通过 MCTP 请求处理器来模拟响应
        m_mctp = mc::make_shared<dev::mctp>(nullptr, 0, dev::MCTP_MESSAGE_TYPE_NCSI, "");
        m_ncsi = std::make_shared<dev::ncsi_over_mctp_mellanox>(*m_mctp);
    }
    void TearDown() override {
        try {
            if (m_metrics) {
                // 先停止定时器任务
                m_metrics->stop_ncsi_update_task();
                // 等待定时器回调完全停止，避免在对象析构时回调仍在执行导致段错误
                std::this_thread::sleep_for(std::chrono::milliseconds(200));
                m_metrics.reset();
            }
            // 清理 MCTP 请求处理器，避免影响其他测试
            dev::set_mctp_request_handler(nullptr);
            m_ncsi.reset();
            m_mctp.reset();
            // 再次等待，确保所有异步操作完成
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
        } catch (...) {
            // 异常情况下也要确保资源释放
            if (m_metrics) {
                m_metrics.reset();
            }
            m_ncsi.reset();
            m_mctp.reset();
        }
    }

    static std::unique_ptr<metrics_test_service> m_test_service;
    static mc::shared_ptr<test_ipmi_core_object> m_ipmi_core_obj;
    mc::shared_ptr<dev::NetworkPort_Metrics>     m_metrics;
    mc::shared_ptr<dev::mctp>                    m_mctp;
    std::shared_ptr<dev::ncsi_over_mctp_mellanox> m_ncsi;
};
std::unique_ptr<metrics_test_service> NetworkPortMetricsTest::m_test_service;
mc::shared_ptr<test_ipmi_core_object> NetworkPortMetricsTest::m_ipmi_core_obj;

// ========================= 基本功能测试 =========================

TEST_F(NetworkPortMetricsTest, Constructor) {
    dev::NetworkPort_Metrics metrics;
    EXPECT_TRUE(true);
}

TEST_F(NetworkPortMetricsTest, Destructor_CleansUpResources) {
    auto metrics = mc::make_shared<dev::NetworkPort_Metrics>();

    // 启动任务后析构
    mc::milliseconds interval(1000);
    uint8_t          port_id    = 0;
    uint8_t          package_id = 0;
    metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    metrics->stop_ncsi_update_task();
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    metrics.reset();

    EXPECT_TRUE(metrics == nullptr);
}

// ========================= update_port_metrics_by_ncsi 测试 =========================

// TEST_F(NetworkPortMetricsTest, UpdatePortMetricsByNcsi_Success) {
//     dev::ncsi_port_metrics_info_t port_metrics = {};
//     port_metrics.rx_frames                      = 1000;
//     port_metrics.tx_frames                      = 2000;
//     port_metrics.rx_unicast_frames              = 500;
//     port_metrics.tx_unicast_frames              = 1000;
//     port_metrics.rx_multicast_frames           = 300;
//     port_metrics.tx_multicast_frames            = 600;
//     port_metrics.rx_broadcast_frames           = 200;
//     port_metrics.tx_broadcast_frames            = 400;
//     port_metrics.rx_fcs_errors                  = 10;
//     port_metrics.rx_under_size_frames          = 5;
//     port_metrics.rx_over_size_frames           = 3;
//     port_metrics.tx_single_collisions           = 2;
//     port_metrics.tx_multiple_collisions        = 1;
//     port_metrics.tx_late_collisions            = 0;
//     port_metrics.tx_excessive_collisions       = 0;
//     port_metrics.rx_frame_alignment_errors     = 1;
//     m_ncsi->set_get_port_metrics_result(true, port_metrics);

//     // 需要先设置 ncsi_over_mctp_mellanox
//     mc::milliseconds interval(1000);
//     uint8_t          port_id    = 0;
//     uint8_t          package_id = 0;
//     m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
//     std::this_thread::sleep_for(std::chrono::milliseconds(50));

//     bool result = m_metrics->update_port_metrics_by_ncsi(port_id);
//     EXPECT_TRUE(result);
//     EXPECT_EQ(m_metrics->RXFrames.get_value(), 1000);
//     EXPECT_EQ(m_metrics->TXFrames.get_value(), 2000);
//     EXPECT_EQ(m_metrics->RXUnicastFrames.get_value(), 500);
//     EXPECT_EQ(m_metrics->TXUnicastFrames.get_value(), 1000);
//     EXPECT_EQ(m_metrics->RXMulticastFrames.get_value(), 300);
//     EXPECT_EQ(m_metrics->TXMulticastFrames.get_value(), 600);
//     EXPECT_EQ(m_metrics->RXBroadcastFrames.get_value(), 200);
//     EXPECT_EQ(m_metrics->TXBroadcastFrames.get_value(), 400);
//     EXPECT_EQ(m_metrics->RXFCSErrors.get_value(), 10);
//     EXPECT_EQ(m_metrics->RXUndersizeFrames.get_value(), 5);
//     EXPECT_EQ(m_metrics->RXOversizeFrames.get_value(), 3);
//     EXPECT_EQ(m_metrics->TXSingleCollisions.get_value(), 2);
//     EXPECT_EQ(m_metrics->TXMultipleCollisions.get_value(), 1);
//     EXPECT_EQ(m_metrics->TXLateCollisions.get_value(), 0);
//     EXPECT_EQ(m_metrics->TXExcessiveCollisions.get_value(), 0);
//     EXPECT_EQ(m_metrics->RXFrameAlignmentErrors.get_value(), 1);
// }

TEST_F(NetworkPortMetricsTest, UpdatePortMetricsByNcsi_GetPortMetricsFailed) {
    // 设置 MCTP 请求处理器返回失败
    dev::set_mctp_request_handler([](const mc::dict&, const std::vector<uint8_t>&, std::string&) {
        return false;
    });

    mc::milliseconds interval(1000);
    uint8_t          port_id    = 0;
    uint8_t          package_id = 0;
    m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    bool result = m_metrics->update_port_metrics_by_ncsi(port_id);
    EXPECT_FALSE(result);
    
    // 停止定时器任务
    m_metrics->stop_ncsi_update_task();
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

TEST_F(NetworkPortMetricsTest, UpdatePortMetricsByNcsi_ZeroValues) {
    // 设置 MCTP 请求处理器，返回全零的端口指标
    dev::set_mctp_request_handler([](const mc::dict& ctx, const std::vector<uint8_t>& data,
                                     std::string& rsp) {
        EXPECT_EQ(ctx.at("PacketType").as<int64_t>(), GET_CONTROLLER_PACKET_STATISTICS);
        EXPECT_TRUE(data.empty());
        // 构造全零响应
        controller_packet_statistics_rsp response{};
        response.rsp_code    = host_to_be16(COMMAND_COMPLETED);
        response.reason_code = host_to_be16(NOERROR_OR_NOREASON);
        // 所有字段都初始化为 0
        std::string result(reinterpret_cast<const char*>(&response), GET_CONTROLLER_PACKET_STATISTICS_RSP_LEN);
        rsp = result;
        return true;
    });

    mc::milliseconds interval(1000);
    uint8_t          port_id    = 0;
    uint8_t          package_id = 0;
    m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    bool result = m_metrics->update_port_metrics_by_ncsi(port_id);
    EXPECT_TRUE(result);
    EXPECT_EQ(m_metrics->RXFrames.get_value(), 0);
    EXPECT_EQ(m_metrics->TXFrames.get_value(), 0);
    EXPECT_EQ(m_metrics->RXFCSErrors.get_value(), 0);
    // 验证任务已启动，可以通过停止来验证
    m_metrics->stop_ncsi_update_task();
    // 等待定时器回调完全停止
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    EXPECT_TRUE(true);
}

TEST_F(NetworkPortMetricsTest, UpdatePortMetricsByNcsi_WithoutNcsiInitialized) {
    // 不启动任务，直接调用 update_port_metrics_by_ncsi
    uint8_t port_id = 0;
    bool    result  = m_metrics->update_port_metrics_by_ncsi(port_id);
    // 由于 m_ncsi_over_mctp_mellanox 为 nullptr，应该会失败
    EXPECT_FALSE(result);
}

// ========================= start_ncsi_update_task_mellanox 测试 =========================

TEST_F(NetworkPortMetricsTest, StartNcsiUpdateTask_Success) {
    mc::milliseconds interval(1000);
    uint8_t          port_id    = 0;
    uint8_t          package_id = 0;

    m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    // 验证任务已启动，可以通过停止来验证
    m_metrics->stop_ncsi_update_task();
    EXPECT_TRUE(true);
}

TEST_F(NetworkPortMetricsTest, StartNcsiUpdateTask_WithNullNcsi) {
    mc::milliseconds              interval(1000);
    uint8_t                       port_id    = 0;
    uint8_t                       package_id = 0;
    dev::ncsi_over_mctp_mellanox_ptr null_ncsi = nullptr;

    // 应该能正常处理空指针
    m_metrics->start_ncsi_update_task_mellanox(null_ncsi, interval, port_id, package_id);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    m_metrics->stop_ncsi_update_task();
    EXPECT_TRUE(true);
}

TEST_F(NetworkPortMetricsTest, StartNcsiUpdateTask_DifferentIntervals) {
    std::vector<mc::milliseconds> intervals = {mc::milliseconds(100), mc::milliseconds(500),
                                                mc::milliseconds(1000)};
    uint8_t                        port_id    = 0;
    uint8_t                        package_id = 0;

    for (auto& interval : intervals) {
        m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
        m_metrics->stop_ncsi_update_task();
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    EXPECT_TRUE(true);
}

TEST_F(NetworkPortMetricsTest, StartNcsiUpdateTask_DifferentPortIds) {
    mc::milliseconds interval(1000);
    uint8_t          package_id = 0;
    std::vector<uint8_t> port_ids = {0, 1, 2, 255};

    for (auto port_id : port_ids) {
        m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
        m_metrics->stop_ncsi_update_task();
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    EXPECT_TRUE(true);
}

TEST_F(NetworkPortMetricsTest, StartNcsiUpdateTask_DifferentPackageIds) {
    mc::milliseconds interval(1000);
    uint8_t          port_id = 0;
    std::vector<uint8_t> package_ids = {0, 1, 2, 255};

    for (auto package_id : package_ids) {
        m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
        std::this_thread::sleep_for(std::chrono::milliseconds(50));
        m_metrics->stop_ncsi_update_task();
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    EXPECT_TRUE(true);
}

TEST_F(NetworkPortMetricsTest, StartNcsiUpdateTask_MultipleStarts) {
    mc::milliseconds interval(1000);
    uint8_t          port_id    = 0;
    uint8_t          package_id = 0;

    // 多次启动应该能正常处理
    m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));
    m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    m_metrics->stop_ncsi_update_task();
    EXPECT_TRUE(true);
}

// ========================= stop_ncsi_update_task 测试 =========================

TEST_F(NetworkPortMetricsTest, StopNcsiUpdateTask_WithoutStart) {
    // 未启动时停止应该能正常处理
    m_metrics->stop_ncsi_update_task();
    EXPECT_TRUE(true);
}

TEST_F(NetworkPortMetricsTest, StopNcsiUpdateTask_AfterStart) {
    mc::milliseconds interval(1000);
    uint8_t          port_id    = 0;
    uint8_t          package_id = 0;

    m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    m_metrics->stop_ncsi_update_task();
    std::this_thread::sleep_for(std::chrono::milliseconds(10));
    EXPECT_TRUE(true);
}

TEST_F(NetworkPortMetricsTest, StopNcsiUpdateTask_MultipleStops) {
    mc::milliseconds interval(1000);
    uint8_t          port_id    = 0;
    uint8_t          package_id = 0;

    m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    // 多次停止应该能正常处理
    m_metrics->stop_ncsi_update_task();
    m_metrics->stop_ncsi_update_task();
    m_metrics->stop_ncsi_update_task();
    EXPECT_TRUE(true);
}

// ========================= 多实例测试 =========================

TEST_F(NetworkPortMetricsTest, MultiInstance) {
    std::vector<mc::shared_ptr<dev::NetworkPort_Metrics>> metrics_list;
    for (int i = 0; i < 3; i++) {
        std::string object_name =
            "metrics_" + std::to_string(i) + "_" + std::to_string(std::time(nullptr)) + "_" +
            std::to_string(i * 1000);
        std::string position = std::to_string(i + 4000);

        auto metrics = mc::make_shared<dev::NetworkPort_Metrics>();

        mc::milliseconds interval(1000);
        uint8_t          port_id    = i;
        uint8_t          package_id = i;
        metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
        metrics_list.push_back(metrics);
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(50));

    for (auto& metrics : metrics_list) {
        if (metrics && m_test_service) {
            try {
                metrics->stop_ncsi_update_task();
                // 等待每个定时器回调完全停止
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
            } catch (...) {
            }
        }
    }
    metrics_list.clear();
    // 等待所有异步操作完成，确保定时器回调完全停止
    std::this_thread::sleep_for(std::chrono::milliseconds(150));
    EXPECT_TRUE(true);
}

// ========================= 综合测试 =========================

// TEST_F(NetworkPortMetricsTest, CompleteWorkflow) {
//     // 1. 设置 mock 返回值
//     dev::ncsi_port_metrics_info_t port_metrics = {};
//     port_metrics.rx_frames                      = 10000;
//     port_metrics.tx_frames                      = 20000;
//     port_metrics.rx_unicast_frames              = 5000;
//     port_metrics.tx_unicast_frames              = 10000;
//     port_metrics.rx_multicast_frames           = 3000;
//     port_metrics.tx_multicast_frames            = 6000;
//     port_metrics.rx_broadcast_frames           = 2000;
//     port_metrics.tx_broadcast_frames            = 4000;
//     port_metrics.rx_fcs_errors                  = 50;
//     port_metrics.rx_under_size_frames          = 20;
//     port_metrics.rx_over_size_frames           = 10;
//     port_metrics.tx_single_collisions           = 5;
//     port_metrics.tx_multiple_collisions        = 2;
//     port_metrics.tx_late_collisions            = 1;
//     port_metrics.tx_excessive_collisions       = 0;
//     port_metrics.rx_frame_alignment_errors     = 3;
//     m_ncsi->set_get_port_metrics_result(true, port_metrics);

//     // 2. 启动任务
//     mc::milliseconds interval(1000);
//     uint8_t          port_id    = 0;
//     uint8_t          package_id = 0;
//     m_metrics->start_ncsi_update_task_mellanox(m_ncsi, interval, port_id, package_id);
//     std::this_thread::sleep_for(std::chrono::milliseconds(50));

//     // 3. 手动更新端口指标
//     bool result = m_metrics->update_port_metrics_by_ncsi(port_id);
//     EXPECT_TRUE(result);
//     EXPECT_EQ(m_metrics->RXFrames.get_value(), 10000);
//     EXPECT_EQ(m_metrics->TXFrames.get_value(), 20000);

//     // 4. 停止任务
//     m_metrics->stop_ncsi_update_task();
//     // 等待足够长的时间，确保定时器回调完成，避免在 TearDown 时回调仍在执行
//     std::this_thread::sleep_for(std::chrono::milliseconds(200));
//     EXPECT_TRUE(true);
// }

} // namespace test
} // namespace interface
} // namespace mellanox
} // namespace pcie_nic_card
} // namespace drivers

